﻿namespace Atomic.Modules.Security
{
    using System;
    using System.Linq;
    using System.Collections.Generic;

    /// <summary>
    /// 授权者。
    /// </summary>
    public class Authorizer : IAuthorizer
    {
        /// <summary>
        /// 权限提供程序。
        /// </summary>
        private readonly IPermissionProvider _permissionProvider = null;

        /// <summary>
        /// 用户认证服务。
        /// </summary>
        private readonly IAuthenticationService _authenticationService = null;

        /// <summary>
        /// 构造器。
        /// </summary>
        /// <param name="permissionProvider">权限提供程序。</param>
        /// <param name="authenticationService">用户认证服务。</param>
        public Authorizer(IPermissionProvider permissionProvider, IAuthenticationService authenticationService)
        {
            this._permissionProvider = permissionProvider;
            this._authenticationService = authenticationService;
        }

        /// <summary>
        /// 授权。
        /// </summary>
        /// <param name="permission">权限信息。</param>
        public bool Authorize(Permission permission)
        {
            if (permission == null)
            {
                throw new ArgumentNullException("permission", "传入的权限信息不可以是空。");
            }

            return Authorize(permission.Name);
        }

        /// <summary>
        /// 授权验证。
        /// </summary>
        /// <remarks>
        /// 1、获取当前用户的信息。
        /// 1.1、如果是已登录的则获取当前登录用户的信息。
        /// 1.2、如果是未登录的则获取匿名用户的信息。
        /// 2、获取当前用户的所有角色的权限信息并且合并成一个集合。
        /// 3、判断该权限集合里是否存在指定的权限。
        /// 4、如果用户是被禁用的，则只根本禁封用户拥有的权限来判断用户可用权限。
        /// </remarks>
        /// <param name="permissionName">权限编号。</param>
        /// <returns>已授权返回 true，未授权返回 false。</returns>
        public bool Authorize(string permissionName)
        {
            var user = this._authenticationService.GetAuthenticatedUser();

            if (user != null)
            {
                if (user.Disable)
                {
                    return user.Roles.SelectMany(role => role.Permissions).Any(permission => permission.Name == permissionName);
                }
                else
                {
                    return this._permissionProvider.GetRole((int)SystemRoles.Disable).Permissions.Any(permission => permission.Name == permissionName);
                }
            }

            return false;
        }
    }
}